<?php
// +----------------------------------------------------------------------
// | RXThinkCMF敏捷开发框架 [ 赋能开发者，助力企业发展 ]
// +----------------------------------------------------------------------
// | 版权所有 2018~2023 南京RXThinkCMF研发中心
// +----------------------------------------------------------------------
// | Licensed LGPL-3.0 RXThinkCMF并不是自由软件，未经许可禁止去掉相关版权
// +----------------------------------------------------------------------
// | 官方网站: https://www.rxthink.cn
// +----------------------------------------------------------------------
// | Author: @牧羊人 团队荣誉出品
// +----------------------------------------------------------------------
// | 版权和免责声明:
// | 本团队对该软件框架产品拥有知识产权（包括但不限于商标权、专利权、著作权、商业秘密等）
// | 均受到相关法律法规的保护，任何个人、组织和单位不得在未经本团队书面授权的情况下对所授权
// | 软件框架产品本身申请相关的知识产权，禁止用于任何违法、侵害他人合法权益等恶意的行为，禁
// | 止用于任何违反我国法律法规的一切项目研发，任何个人、组织和单位用于项目研发而产生的任何
// | 意外、疏忽、合约毁坏、诽谤、版权或知识产权侵犯及其造成的损失 (包括但不限于直接、间接、
// | 附带或衍生的损失等)，本团队不承担任何法律责任，本软件框架禁止任何单位和个人、组织用于
// | 任何违法、侵害他人合法利益等恶意的行为，如有发现违规、违法的犯罪行为，本团队将无条件配
// | 合公安机关调查取证同时保留一切以法律手段起诉的权利，本软件框架只能用于公司和个人内部的
// | 法律所允许的合法合规的软件产品研发，详细声明内容请阅读《框架免责声明》附件；
// +----------------------------------------------------------------------

namespace app\admin\service;

use app\admin\model\Schoole;
use app\admin\model\Classes;
use app\admin\model\Student;
use app\admin\model\Teacher;
use think\Db;
use think\Exception;

/**
 * 班级管理-服务类
 * @author 牧羊人
 * @since: 2024/06/25
 * Class ClassesService
 * @package app\admin\service
 */
class ClassesService extends BaseService
{

    // 用户ID
    protected $userId = 0;
    public static $staticUserId = 0;

    /**
     * 构造函数
     * LevelService constructor.
     */
    public function __construct()
    {
        $this->model = new Classes();

        // 解析Token获取用户ID
        $token = request()->header("Authorization");
        $token = str_replace("Bearer ", null, $token);
        $jwt = new \Jwt();
        $this->userId = $jwt->verifyToken($token);
    }

    /**
     * 删除记录
     * @return array
     * @since 2020/11/12
     * @author 牧羊人
     */
    public function delete()
    {
        return $this->remove(function ($info) {
            $stu = (new Student)
                ->distinct(true)
                ->where('schoole_id', reset($info)['schoole_id'])
                ->where('grade_id', 'in', array_column($info, 'grade_id'))
                ->where('class_id', 'in', array_column($info, 'class_key'))
                ->where('mark', 1)
                ->column('class_id');
            if ($stu) {
                throw new \Exception( '选中的数据中有班级存在学生');
            }
        });
    }

    /**
     * 获取数据列表
     * @return array
     * @since 2024/06/25
     * @author 牧羊人
     */
    public function getList($page = 0, $limit = 10)
    {
        $param = request()->param();

        // 获取参数值
        $schoole_id = getter($param, "schoole_id", 0);
        $grade_id = getter($param, "grade_id", '');
        $class_id = getter($param, "class_id", '');
        $title = getter($param, "keyword", '');
        //$keyword = getter($param, "keyword", '');

        // 查询条件
        $map = [];

        if ($schoole_id) $map[] = ['schoole_id', '=', $schoole_id];
        if ($grade_id !== '') $map[] = ['grade_id', '=', $grade_id];
        if ($class_id !== '') $map[] = ['class_key', '=', $class_id];
        //if ($title !== '') $map[] = ['title', '=', generate_class($title)];
        if ($title !== '') $map[] = ['title', 'like', "%{$title}%"];
        //if ($keyword) $map[] = ['realname|username|mobile', 'like', '%' . $keyword . '%'];

        $map[] = ['mark', '=', 1];  //有效标识 = 1

        $sort = 'sort desc,id desc';

        $page = $page ?: request()->param('page', 1);
        $limit = $limit ?: request()->param('limit', 20);
        $teacher = getTeacher($this->userId);
        if ($teacher) {
            $query = $this->model->with(['schoole'])
                ->where('find_in_set(' . $teacher['id'] . ',teacher_ids)')
                ->where($map);
        } else {
            $schoolRole = SchoolRoleMap($this->userId, 'schoole_id');
            if ($schoolRole) {
                $map[] = $schoolRole;
            }
            $query = $this->model->with(['schoole'])->where($map);
        }


        $count = $query->count();
        $list = $query->order($sort)->page($page, $limit)->select()->append(['teacher', 'student_count']);

        $res = [
            "msg" => '获取成功',
            "code" => 0,
            "count" => $count,
            "data" => $list,
        ];

        return $res;
    }

    /**
     * 获取班级考勤 - 按日期或月份筛选查询考勤情况数据列表
     * @return array
     * @since 2024/06/25
     * @author 牧羊人
     */
    public function getWorkList($page = 0, $limit = 10)
    {
        $param = request()->param();

        $action = request()->action();  //获取请求的方法名

        // 获取参数值
        $schoole_id = getter($param, "schoole_id", '');
        $grade_id = getter($param, "grade_id", '');
        $class_id = getter($param, "class_id", '');
        $gender = getter($param, "gender", '');
        $keywords = getter($param, "keywords", '');
        $day_time = getter($param, "day_time", date('Y-m-d'));
        $month_time = getter($param, "month_time", date('Y-m'));

        // 查询条件
        $map = [];

        if ($schoole_id) $map[] = ["schoole_id", "=", $schoole_id];
        if ($grade_id) $map[] = ["grade_id", "=", $grade_id];
        if ($class_id) $map[] = ["class_id", "=", $class_id];
        if ($gender !== '') $map[] = ["gender", "=", $gender];
        $map[] = ["think_student.mark", "=", 1];
        if ($keywords) $map[] = ["imei|name|id_card|student_no|sim_no|phone", "like", '%' . $keywords . '%'];

        $page = $page ?: request()->param('page', 1);
        $limit = $limit ?: request()->param('limit', 20);

        // 日统计只显示是否到校，按work_count > 0 ? 是 ：否。月统计显示到校次数(work_count)，缺勤次数(absence_count)。
        $query = app()->make(Student::class)->with(['schoole'])->withCount([
            'work' => function ($query) use ($action, $day_time, $month_time) {
                if ($action == 'daywork' || $action == 'dayworkexportexcel') {
                    $query->where('day', str_replace('-', '', $day_time))->where('school_arrive_time', '>', 0);
                } else {
                    $query->where('month', str_replace('-', '', $month_time))->where('school_arrive_time', '>', 0);
                }
            }
        ])->where($map);
        $count = $query->count();
        $list = $query->page($page, $limit)->select()->append(['grade_title', 'class_title']);

        if ($action == 'monthwork' || $action == 'monthworkexportexcel') {
            //$work_day = countWeekdaysInMonth(explode('-', $month_time)[0], explode('-', $month_time)[1]) -
              //  countHolidaysInMonth($month_time, true, true);
               /* $arr = range(1,date('d'));
                $work_day = count($arr);*/
            foreach ($list as &$item) {
                if ($action == 'daywork' || $action == 'dayworkexportexcel') {
                    $work_count = Db::table('think_student_work_log')
                        ->where('student_id',$item['id'])
                        ->where('day', str_replace('-', '', $day_time))
                        ->where('school_arrive_time', '>', 0)
                        ->group('day')
                        ->count();
                } else {
                    $work_count = Db::table('think_student_work_log')
                        ->where('student_id',$item['id'])
                        ->where('month', str_replace('-', '', $month_time))
                        ->where('school_arrive_time', '>', 0)
                        ->group('day')
                        ->count();;
                }
                $item['work_count'] = $work_count;
                $item['absence_count'] = workday() - $work_count;
            }
        }

        $res = [
            "msg" => '获取成功',
            "code" => 0,
            "action" => $action,
            "params" => [
                'day_time' => $day_time,
                'month_time' => $month_time
            ],
            "count" => $count,
            "data" => $list,
        ];

        return $res;
    }

    /**
     * 添加或编辑
     * @return mixed
     * @since 2020/11/20
     * @author 牧羊人
     */
    public function edit()
    {
        // 请求参数
        $data = request()->param();
        $data['class_key'] = str_replace('班', '', $data['title']);
        $data['title'] = generate_class($data['class_key']);
        if(empty($data['id'])){
            $smap2 = [
                'grade_id' => $data['grade_id'],
                'schoole_id' => $data['schoole_id'],
                'class_key' => $data['class_key'],
                'mark' => 1
            ];
            $row2 = Db::table('think_class')->where($smap2)
                ->where('')
                ->find();
             if($row2){
                 return message("重复添加", false);
             }
        }else{

            $smap1 = [
                'grade_id' => $data['grade_id'],
                'schoole_id' => $data['schoole_id'],
                'class_key' => $data['class_key'],
                'mark' => 1
            ];
            $row1 = Db::table('think_class')->where($smap1)
                ->find();
            if($row1 && $row1['id'] != $data['id']){
                return message("重复添加", false);
            }
            $smap = [
                'grade_id' => $data['grade_id'],
                'schoole_id' => $data['schoole_id'],
                'class_key' => $data['class_key'],
                'mark' => 1
            ];
            if(is_array($data['teacher_id'])){
                $ids = $data['teacher_id'];
                sort($ids);
                $data['teacher_ids'] = implode(',',$ids);
                $smap += ['teacher_ids' => $data['teacher_ids']];
            }
            $row = Db::table('think_class')->where($smap)
                //->where('find_in_set(' . $data['teacher_ids']. ',teacher_ids) ')
                ->where('')
                ->find();
            if($row['id'] == $data['id'] && $row['grade_id'] == $data['grade_id']){
                return parent::edit($data); // TODO: Change the autogenerated stub
            }
            if($row1 && $row){
                return message("重复添加", false);
            }
        }

        return parent::edit($data); // TODO: Change the autogenerated stub
    }

    /**
     * 导入Excel
     */
    public function importExcel()
    {
        //学校ID
        $schoole_id = request()->param('schoole_id', '');
        if (!$schoole_id) return message("缺少学校ID(schoole_id)参数值", false);

        $schoole = app()->make(Schoole::class)->get($schoole_id);
        if (!$schoole) return message("该学校不存在", false);

        // 检查文件扩展名
        $file = $_FILES['file'];
        if (!$file) return message("请上传文件", false);

        $extension = pathinfo($file['name'], PATHINFO_EXTENSION);
        if (strtolower($extension) !== 'xlsx') return message("上传的文件必须是 .xlsx 格式。", false);

        $error = "";
        // 上传文件(非图片)
        $result = upload_file('file', 'import/', $error);
        if (!$result) return message($error, false);

        // 文件路径
        $filePath = FILE_PATH . $result;
        if (!file_exists($filePath)) return message("文件不存在", false);

        // 读取文件
        $objPHPExcel = \PHPExcel_IOFactory::load($filePath); //获取sheet表格数目
        $sheetSelected = 0;
        $objPHPExcel->setActiveSheetIndex($sheetSelected); //获取表格行数
        $activeSheet = $objPHPExcel->getActiveSheet();
        $rowCount = $activeSheet->getHighestRow(); //获取表格列数
        $columnCount = $activeSheet->getHighestColumn();
        $totalNum = $rowCount - 1;

        //验证文件内容
        if ($totalNum < 1) return message("请填写数据后上传", false);
        if ($columnCount !== 'C' && $columnCount !== 'D') return message("请不要更改模板文件格式，填写数据后上传", false);

        $dataArr = array();
        $create_user = $this->userId;
        $create_time = time();

        // 循环读取行数据
        $classKeys = $gradeIds = $teacherIds = $exists = [];
        for ($row = 2; $row <= $rowCount; $row++) {
            // 获取列值
            $grade = trim($activeSheet->getCell("A" . $row)->getValue());
            if (!$grade) return message(sprintf('第%s行，年级名称未填写', $row), false);
            $grade_id = generate_grade($grade, true);
            $gradeIds[] = $grade_id;

            $title = trim($activeSheet->getCell("B" . $row)->getValue());
            if (!$title) return message(sprintf('第%s行，班级名称未填写', $row), false);

            $class_key = generate_class($title, true);
            $classKeys[] = $class_key;

            $existsKey = $grade_id . '-' . $class_key;
            if (in_array($existsKey, $exists)) {
                return message(sprintf('第%d行，班级重复', $row), false);
            }
            $exists[] = $existsKey;

            $teacher_ids = trim($activeSheet->getCell("C" . $row)->getValue());
            $teacherIds = array_merge($teacherIds, explode(',', $teacher_ids));

            $sort = trim($activeSheet->getCell("D" . $row)->getValue()) ?: 0;

            $dataArr[] = compact('grade_id', 'class_key', 'title', 'sort', 'teacher_ids', 'schoole_id', 'create_user', 'create_time');
        }
        $existsTemp = $this->model
            ->field(['grade_id', 'class_key'])
            ->where('schoole_id', $schoole_id)
            ->whereIn('grade_id', $gradeIds)
            ->whereIn('class_key', $classKeys)
            ->where('mark', 1)
            ->select()
            ->toArray();
        $exists = [];
        foreach ($existsTemp as $val) {
            $exists[] = $val['grade_id'] . '-' . $val['class_key'];
        }
        $teachers = Teacher::where('schoole_id', $schoole_id)->whereIn('id', $teacherIds)->column('id');
        foreach ($dataArr as $key => $val) {
            if (in_array($val['grade_id'] . '-' . $val['class_key'], $exists)) {
                return message(sprintf('第%d行，班级重复', $key + 2), false);
            }
            $teacherIds = explode(',', $val['teacher_ids']);
            $teacherErr = [];
            foreach ($teacherIds as $teacherId) {
                if (!in_array($teacherId, $teachers)) {
                    $teacherErr[] = $teacherId;
                }
            }
            if ($teacherErr) {
                return message(sprintf('第%d行，教师id错误:%s', $key + 2, implode(',', $teacherErr)), false);
            }
        }

        Db::startTrans();
        try {
            $this->model->saveAll($dataArr);
            Db::commit();
        } catch (\Throwable $e) {
            Db::rollback();
            trace('导入老师异常：' . $e->getTraceAsString(), 'error');
            return message($e->getMessage(), false);
        }

        return message("本次成功导入{$totalNum}条数据");
    }

    /**
     * 导出Excel
     * @throws \PHPExcel_Exception
     * @throws \PHPExcel_Reader_Exception
     * @throws \PHPExcel_Writer_Exception
     */
    public function exportExcel()
    {
        set_time_limit(0);
        $export_type = request()->param('export_type', 0);
        $schoole_id = request()->param('schoole_id', '');
        $schoole_name = '';

        // 获取导出的数据源
        $res = $this->getList(1, 20000);
        $list = $res['data'];

        // 实例化PHPExcel类
        $objPHPExcel = new \PHPExcel();
        // 激活当前的sheet表
        $activeSheet = $objPHPExcel->setActiveSheetIndex(0);
        //5.设置表格头（即excel表格的第一行）
        $activeSheet->setCellValue('A1', '学校')
            ->setCellValue('B1', '年级')
            ->setCellValue('C1', '班级')
            ->setCellValue('D1', '班级老师')
            ->setCellValue('E1', '班级人数')
            ->setCellValue('F1', '创建时间');

        // 设置单元格宽度
        $activeSheet->getColumnDimension('A')->setWidth(80);
        $activeSheet->getColumnDimension('B')->setWidth(20);
        $activeSheet->getColumnDimension('C')->setWidth(20);
        $activeSheet->getColumnDimension('D')->setWidth(80);
        $activeSheet->getColumnDimension('E')->setWidth(80);
        $activeSheet->getColumnDimension('F')->setWidth(80);


        // 循环刚取出来的数组，将数据逐一添加到excel表格
        for ($i = 0; $i < count($list); $i++) {
            $activeSheet->setCellValue('A' . ($i + 2), $list[$i]['schoole_name']);
            $activeSheet->setCellValue('B' . ($i + 2), generate_grade($list[$i]['grade_id']));
            $activeSheet->setCellValue('C' . ($i + 2), $list[$i]['title']);

            $teacher = [];
            foreach ($list[$i]['teacher'] as $key => $val) {
                array_push($teacher, $val['realname'] . ' ' . $val['mobile']);
            }
            $activeSheet->setCellValue('D' . ($i + 2), implode('、', $teacher));
            $activeSheet->setCellValue('E' . ($i + 2), $list[$i]['student_count']);
            $activeSheet->setCellValue('F' . ($i + 2), date('Y-m-d H:i:s', $list[$i]['create_time']));
            $schoole_name = $list[$i]['schoole_name'];
        }
        // 设置保存的Excel表格名称
        $filename = $schoole_name . '_班级导出_' . date('YmdHis', time()) . ".xlsx";
        // 设置当前激活的sheet表格名称
        $activeSheet->setTitle('Sheet1');

        if ($export_type) { //直接浏览器输出
            header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
            header('Content-Disposition: attachment;filename="' . $filename);
            header('Cache-Control: max-age=0');
            // If you're serving to IE 9, then the following may be needed
            header('Cache-Control: max-age=1');
            // If you're serving to IE over SSL, then the following may be needed
            header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); // Date in the past
            header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT'); // always modified
            header('Cache-Control: cache, must-revalidate'); // HTTP/1.1
            header('Pragma: public'); // HTTP/1.0
            $objWriter = \PHPExcel_IOFactory::createWriter($objPHPExcel, 'Excel2007');
            $objWriter->save('php://output');
            return;
        }

        // 保存本地文件
        $objWriter = \PHPExcel_IOFactory::createWriter($objPHPExcel, 'Excel2007');
        $file_dir = UPLOAD_TEMP_PATH . "/" . $schoole_id . "/";
        $savePath = $file_dir . $filename;

        // 检测文件路径是否存在,不存在则创建
        if (!file_exists($file_dir)) {
            mkdirs($file_dir, 0777, true);
        }
        $objWriter->save($savePath);

        // 文件地址
        $filePath = get_image_url(str_replace(PUBLIC_PATH, "", $savePath));
        return message("操作成功", true, $filePath);
    }

    // 班级考勤 - 按日期或月份筛选查询考勤情况并导出Excel
    public function workExportExcel()
    {
        set_time_limit(0);
        $export_type = request()->param('export_type', 0);
        $schoole_id = request()->param('schoole_id', '');
        $grade_id = request()->param('grade_id', '');
        $class_id = request()->param('class_id', '');

        $file_name = '';

        // 获取导出的数据源
        $res = $this->getWorkList(1, 20000);
        $list = $res['data'];

        // 实例化PHPExcel类
        $objPHPExcel = new \PHPExcel();
        // 激活当前的sheet表
        $activeSheet = $objPHPExcel->setActiveSheetIndex(0);
        //5.设置表格头（即excel表格的第一行）
        if ($res['action'] == 'dayworkexportexcel') {
            $activeSheet->setCellValue('A1', '姓名')
                ->setCellValue('B1', '学号')
                ->setCellValue('C1', '身份证号')
                ->setCellValue('D1', '性别')
                ->setCellValue('E1', '年级')
                ->setCellValue('F1', '班级')
                ->setCellValue('G1', '是否到校')
                ->setCellValue('H1', '统计时间');

            // 设置单元格宽度
            $activeSheet->getColumnDimension('A')->setWidth(80);
            $activeSheet->getColumnDimension('B')->setWidth(20);
            $activeSheet->getColumnDimension('C')->setWidth(20);
            $activeSheet->getColumnDimension('D')->setWidth(80);
            $activeSheet->getColumnDimension('E')->setWidth(80);
            $activeSheet->getColumnDimension('F')->setWidth(80);
            $activeSheet->getColumnDimension('G')->setWidth(80);
            $activeSheet->getColumnDimension('H')->setWidth(80);
        } else {
            $activeSheet->setCellValue('A1', '姓名')
                ->setCellValue('B1', '学号')
                ->setCellValue('C1', '身份证号')
                ->setCellValue('D1', '性别')
                ->setCellValue('E1', '年级')
                ->setCellValue('F1', '班级')
                ->setCellValue('G1', '到校次数')
                ->setCellValue('H1', '缺勤次数')
                ->setCellValue('I1', '统计时间');

            // 设置单元格宽度
            $activeSheet->getColumnDimension('A')->setWidth(80);
            $activeSheet->getColumnDimension('B')->setWidth(20);
            $activeSheet->getColumnDimension('C')->setWidth(20);
            $activeSheet->getColumnDimension('D')->setWidth(80);
            $activeSheet->getColumnDimension('E')->setWidth(80);
            $activeSheet->getColumnDimension('F')->setWidth(80);
            $activeSheet->getColumnDimension('G')->setWidth(80);
            $activeSheet->getColumnDimension('H')->setWidth(80);
            $activeSheet->getColumnDimension('I')->setWidth(80);
        }

        $gender_arr = ['保密', '男', '女'];

        // 循环刚取出来的数组，将数据逐一添加到excel表格
        for ($i = 0; $i < count($list); $i++) {
            $activeSheet->setCellValue('A' . ($i + 2), $list[$i]['name']);
            $activeSheet->setCellValue('B' . ($i + 2), $list[$i]['student_no']);
            $activeSheet->setCellValue('C' . ($i + 2), $list[$i]['id_card']);
            $activeSheet->setCellValue('D' . ($i + 2), $gender_arr($list[$i]['gender']));
            $activeSheet->setCellValue('E' . ($i + 2), generate_grade($list[$i]['grade_id']));
            $activeSheet->setCellValue('F' . ($i + 2), generate_class($list[$i]['class_id']));

            if ($res['action'] == 'dayworkexportexcel') {
                $activeSheet->setCellValue('G' . ($i + 2), $list[$i]['work_count'] ? '是' : '否');
                $activeSheet->setCellValue('H' . ($i + 2), $res['params']['day_time']);
            } else {
                $activeSheet->setCellValue('G' . ($i + 2), $list[$i]['work_count']);
                $activeSheet->setCellValue('H' . ($i + 2), $list[$i]['absence_count']);
                $activeSheet->setCellValue('I' . ($i + 2), $res['params']['month_time']);
            }

            $file_name = $list[$i]['schoole_name'] . '_' . generate_grade($list[$i]['grade_id']) . '-' . generate_class($list[$i]['class_id']);
        }
        // 设置保存的Excel表格名称
        $filename = $file_name . '_班级考勤统计情况导出_' . date('YmdHis', time()) . ".xlsx";
        // 设置当前激活的sheet表格名称
        $activeSheet->setTitle('Sheet1');

        if ($export_type) { //直接浏览器输出
            header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
            header('Content-Disposition: attachment;filename="' . $filename);
            header('Cache-Control: max-age=0');
            // If you're serving to IE 9, then the following may be needed
            header('Cache-Control: max-age=1');
            // If you're serving to IE over SSL, then the following may be needed
            header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); // Date in the past
            header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT'); // always modified
            header('Cache-Control: cache, must-revalidate'); // HTTP/1.1
            header('Pragma: public'); // HTTP/1.0
            $objWriter = \PHPExcel_IOFactory::createWriter($objPHPExcel, 'Excel2007');
            $objWriter->save('php://output');
            return;
        }

        // 保存本地文件
        $objWriter = \PHPExcel_IOFactory::createWriter($objPHPExcel, 'Excel2007');
        $file_dir = UPLOAD_TEMP_PATH . "/" . $schoole_id . $grade_id . $class_id . "/";
        $savePath = $file_dir . $filename;

        // 检测文件路径是否存在,不存在则创建
        if (!file_exists($file_dir)) {
            mkdirs($file_dir, 0777, true);
        }
        $objWriter->save($savePath);

        // 文件地址
        $filePath = get_image_url(str_replace(PUBLIC_PATH, "", $savePath));
        return message("操作成功", true, $filePath);
    }
}
